<template>
    <div :class="`${prefixCls}-image`">
        <slot v-if="loading" name="placeholder">
            <div :class="`${prefixCls}-image-placeholder`"></div>
        </slot>
        <slot v-else-if="error" name="error">
            <div :class="`${prefixCls}-image-error`">加载失败</div>
        </slot>
        <img v-else 
            class="mj-image-inner" 
            v-bind="$attrs" 
            v-on="$listeners" 
            @click="clickHandler" 
            :src="src"
            :style="imageStyle" 
            :class="{'mj-image-inner-center': alignCenter}">
    </div>
</template>

<script>
import { prefixCls } from '../prefix'
import './image.css'

const isSupportObjectFit = () => document.documentElement.style.objectFit !== undefined;
const ObjectFit = {
    NONE: 'none',
    CONTAIN: 'contain',
    COVER: 'cover',
    FILL: 'fill',
    SCALE_DOWN: 'scale-down'
}
export default {
    name: `${prefixCls}Image`,
    props: {
        src: String,
        fit: String,
        lazy: Boolean
    },
    data() {
        return {
            prefixCls: prefixCls,
            loading: true,
            error: false,
            show: !this.lazy,
            imageWidth: 0,
            imageHeight: 0
        }
    },
    computed: {
        imageStyle() {
            const { fit } = this;
            if (!this.$isServer && fit) {
                return isSupportObjectFit() ? { 'object-fit': fit } : this.getImageStyle(fit);
            }
            return {};
        },
        alignCenter() {
            return !this.$isServer && !isSupportObjectFit() && this.fit !== ObjectFit.FILL;
        }
    },
    watch: {
        src(val) {
            this.loadImage();
        }
    },
    mounted() {
        this.loadImage();
    },
    methods: {
        loadImage() {
            if (this.$isServer) return;

            // 重置状态
            this.loading = true;
            this.error = false;

            //生成HTMLImageElement实例
            const img = new Image();
            img.onload = e => this.handleLoad(e, img);
            img.onerror = this.handleError.bind(this);

            // 绑定html-attrs 
            Object.keys(this.$attrs).forEach((key) => {
                const value = this.$attrs[key];
                img.setAttribute(key, value);
            });
            img.src = this.src;
        },
        //图片加载成功
        handleLoad(e, img) {
            this.imageWidth = img.width;
            this.imageHeight = img.height;
            this.loading = false;
            this.error = false;
        },
        //图片加载失败
        handleError(e) {
            this.loading = false;
            this.error = true;
            this.$emit('error', e);
        },
        getImageStyle(fit) {
            const { imageWidth, imageHeight } = this;
            const { clientWidth: containerWidth, clientHeight: containerHeight } = this.$el;

            if (!imageWidth || !imageHeight || !containerWidth || !containerHeight) return {};

            const imageAspectRatio = imageWidth / imageHeight;
            const containerAspectRatio = containerWidth / containerHeight;

            if (fit === ObjectFit.SCALE_DOWN) {
                const isSmaller = imageWidth < containerWidth && imageHeight < containerHeight;
                fit = isSmaller ? ObjectFit.NONE : ObjectFit.CONTAIN;
             }

            switch (fit) {
                case ObjectFit.NONE:
                    return { width: 'auto', height: 'auto' };
                case ObjectFit.CONTAIN:
                    return (imageAspectRatio < containerAspectRatio) ? { width: 'auto' } : { height: 'auto' };
                case ObjectFit.COVER:
                    return (imageAspectRatio < containerAspectRatio) ? { height: 'auto' } : { width: 'auto' };
                default:
                    return {};
            }
        },
        clickHandler(event) {
            this.$emit('on-image', event)
        },
    },
}
</script>

<style  scoped>
</style>
